package be.android.forap.crypto;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Date;
import java.util.Iterator;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedDataList;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
import org.bouncycastle.openpgp.PGPObjectFactory;
import org.bouncycastle.openpgp.PGPOnePassSignatureList;
import org.bouncycastle.openpgp.PGPPBEEncryptedData;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.util.io.Streams;

import be.android.forap.javacard.SecureElement;

import android.os.Environment;
import android.util.Log;

public class PGPEncryption {

	private static int COMPRESSION_ALG = PGPCompressedData.ZIP;
	private static int ENCRYPTION_ALG = PGPEncryptedData.AES_256;

	private static void initialize(){
		if (Security.getProvider("SC") == null)
			Security.addProvider(new BouncyCastleProvider());          
	}

	public static void test() throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, PGPException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, IOException{
		initialize();
		 byte [] v32 ="Komaan werk dan toch dit is bullshit motherfuck".getBytes();
		 byte [] v27 ="Komaan werk dan toch dit is".getBytes();
		 byte [] v30 ="Komaan werk dan toch dit is bs".getBytes();
		 byte [] v15 ="Komaan werk dan".getBytes();
		 byte[] vector = v27;
		Cipher        c = Cipher.getInstance("AES/CFB/NoPadding", "SC");
		Cipher        c2 = Cipher.getInstance("AES/ECB/NoPadding", "SC");
		SecureRandom rand = new SecureRandom();
		SecretKey key = PGPUtil.makeRandomKey(9, rand);
		c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[c.getBlockSize()]), rand);

		c2.init(Cipher.ENCRYPT_MODE, key);
		
		byte[] inLineIv = new byte[c.getBlockSize() + 4];
		//byte[] inLineIv = new byte[c.getBlockSize()];
		//rand.nextBytes(inLineIv);
		inLineIv[inLineIv.length - 1] = inLineIv[inLineIv.length - 3];
		inLineIv[inLineIv.length - 2] = inLineIv[inLineIv.length - 4];
		

		byte[] i = c.update(inLineIv);
		byte[] u = c.update(vector);
		byte[] f = c.doFinal();
		
		SecureElement.initDataEncryption();
		byte[] ii = SecureElement.updateDataEncryption(inLineIv);
		byte[] pt1 = SecureElement.getPTBuffer();
		byte[] uu = SecureElement.updateDataEncryption(vector);
		byte[] pt2 = SecureElement.getPTBuffer();
		byte[] ff = SecureElement.doFinalDataEncryption();
		Log.d("TESTRESULT", "length ="+ pt1.length +" "+ CryptoUtil.toHexNoSpaces(pt1));
		Log.d("TESTRESULT", "length ="+ pt2.length +" "+ CryptoUtil.toHexNoSpaces(pt2));
		Log.d("TESTRESULT", "length ="+ vector.length +" "+ CryptoUtil.toHexNoSpaces(vector));
		Log.d("TESTRESULT", i.length + " "+ CryptoUtil.toHexNoSpaces(i));
		Log.d("TESTRESULT", ii.length + " "+CryptoUtil.toHexNoSpaces(ii));
		Log.d("TESTRESULT", u.length + " "+CryptoUtil.toHexNoSpaces(u));
		Log.d("TESTRESULT", uu.length + " "+CryptoUtil.toHexNoSpaces(uu));

		Log.d("TESTRESULT", f.length + " "+CryptoUtil.toHexNoSpaces(f));
		Log.d("TESTRESULT", ff.length + " "+CryptoUtil.toHexNoSpaces(ff));
		Log.d("TESTRESULT", f.length + " "/*+/*CryptoUtil.toHexNoSpaces(f)*/);
		Log.d("TESTRESULT", ff.length + " "/*+CryptoUtil.toHexNoSpaces(ff))*/);
		
		byte[] pt = new byte[13];
		for(int k =0;k<pt.length;k++){
			
			pt[k] =vector[vector.length-pt.length+k];
		}
		Log.d("TESTRESULT", pt.length + " "+CryptoUtil.toHexNoSpaces(pt));
		
		byte[] up = new byte[16];
		for(int j = 0;j<16;j++){
			up[j]=u[u.length-16+j];
		}
		Log.d("TESTRESULT", up.length + " "+CryptoUtil.toHexNoSpaces(up));
		byte[]uout = c2.update(up);
		byte[] uxor = new byte[uout.length];
		Log.d("TESTRESULT", uout.length + " "+CryptoUtil.toHexNoSpaces(uout));
		for(int k =0;k<uout.length;k++){
			
			uxor[k] = (byte) (uout[k] ^ vector[vector.length-1]);
		}
		Log.d("TESTRESULT", uxor.length + " "+CryptoUtil.toHexNoSpaces(uxor));
		
		/*byte[] fxor = new byte[f.length];
		byte[] ffxor = new byte[f.length];
		byte[] fxorrev = new byte[f.length];
		byte[] ffxorrev = new byte[f.length];
		int offset = vector.length - f.length; 
		for(int k =0;k<f.length;k++){
			fxor[k] = (byte) (f[k] ^ vector[offset+k]);
			ffxor[k] = (byte) (ff[k] ^ vector[offset+k]);
			fxorrev[k] = (byte) (f[k] ^ vector[vector.length-1-k]);
			ffxorrev[k] = (byte) (ff[k] ^ vector[vector.length-1-k]);
		}
		
		Log.d("TESTRESULT", "XOR "+CryptoUtil.toHexNoSpaces(fxor));
		Log.d("TESTRESULT", "XOR "+CryptoUtil.toHexNoSpaces(ffxor));
		Log.d("TESTRESULT", "XOR "+CryptoUtil.toHexNoSpaces(fxorrev));
		Log.d("TESTRESULT", "XOR "+CryptoUtil.toHexNoSpaces(ffxorrev));
		*/
	}
	
	
	public static void changeAlgorithms(int compressionAlg,int encryptionAlg){
		COMPRESSION_ALG = compressionAlg;
		ENCRYPTION_ALG = encryptionAlg;
	}



	public static void encryptFile(String outputFileName, String inputFileName, String encKeyFileName,
			boolean armor, boolean withIntegrityCheck)
					throws IOException, NoSuchProviderException, PGPException{
		OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFileName));
		PGPPublicKey encKey = readPublicKey(encKeyFileName);
		encryptFile(out, inputFileName, encKey, armor, withIntegrityCheck);
		out.close();

	}

	private static void encryptFile(OutputStream out, String fileName,
			PGPPublicKey encKey, boolean armor, boolean withIntegrityCheck)
					throws IOException, NoSuchProviderException{
		if (armor)
		{
			out = new ArmoredOutputStream(out);
		}

		try
		{
			byte[] bytes = compressFile(fileName, COMPRESSION_ALG);

			PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(ENCRYPTION_ALG, withIntegrityCheck, new SecureRandom(), "SC");
			encGen.addMethod(encKey);

			OutputStream cOut = encGen.open(out, bytes.length);

			cOut.write(bytes);
			cOut.close();

			if (armor)
			{
				out.close();
			}
		}
		catch (PGPException e)
		{
			System.err.println(e);
			if (e.getUnderlyingException() != null)
			{
				e.getUnderlyingException().printStackTrace();
			}
		}

	}
	
	public static void decryptFile(
			String inputFileName,
			String keyFileName,
			char[] passwd,
			String defaultFileName)
					throws IOException, NoSuchProviderException
					{
		InputStream in = new BufferedInputStream(new FileInputStream(inputFileName));
		InputStream keyIn = new BufferedInputStream(new FileInputStream(keyFileName));
		decryptFile(in, keyIn, passwd, defaultFileName);
		keyIn.close();
		in.close();
					}

	/**
	 * decrypt the passed in message stream
	 */
	private static void decryptFile(
			InputStream in,
			InputStream keyIn,
			char[]      passwd,
			String      defaultFileName)
					throws IOException, NoSuchProviderException
					{
		in = PGPUtil.getDecoderStream(in);

		try
		{
			PGPObjectFactory pgpF = new PGPObjectFactory(in);
			PGPEncryptedDataList    enc;

			Object                  o = pgpF.nextObject();
			//
			// the first object might be a PGP marker packet.
			//
			if (o instanceof PGPEncryptedDataList)
			{
				enc = (PGPEncryptedDataList)o;
			}
			else
			{
				enc = (PGPEncryptedDataList)pgpF.nextObject();
			}

			//
			// find the secret key
			//
			Iterator                    it = enc.getEncryptedDataObjects();
			PGPPrivateKey               sKey = null;
			PGPPublicKeyEncryptedData   pbe = null;
			PGPSecretKeyRingCollection  pgpSec = new PGPSecretKeyRingCollection(
					PGPUtil.getDecoderStream(keyIn));

			while (sKey == null && it.hasNext())
			{
				pbe = (PGPPublicKeyEncryptedData)it.next();

				sKey = findSecretKey(pgpSec, pbe.getKeyID(), passwd);
			}

			if (sKey == null)
			{
				throw new IllegalArgumentException("secret key for message not found.");
			}

			InputStream         clear = pbe.getDataStream(sKey, "SC");

			PGPObjectFactory    plainFact = new PGPObjectFactory(clear);

			Object              message = plainFact.nextObject();

			if (message instanceof PGPCompressedData)
			{
				PGPCompressedData   cData = (PGPCompressedData)message;
				PGPObjectFactory    pgpFact = new PGPObjectFactory(cData.getDataStream());

				message = pgpFact.nextObject();
			}

			if (message instanceof PGPLiteralData)
			{
				PGPLiteralData ld = (PGPLiteralData)message;

				String outFileName = ld.getFileName();
				if (outFileName.length() == 0)
				{
					outFileName = defaultFileName;
				}

				InputStream unc = ld.getInputStream();
				OutputStream fOut = new BufferedOutputStream(new FileOutputStream(outFileName));

				Streams.pipeAll(unc, fOut);

				fOut.close();
			}
			else if (message instanceof PGPOnePassSignatureList)
			{
				throw new PGPException("encrypted message contains a signed message - not literal data.");
			}
			else
			{
				throw new PGPException("message is not a simple encrypted file - type unknown.");
			}

			if (pbe.isIntegrityProtected())
			{
				if (!pbe.verify())
				{
					System.err.println("message failed integrity check");
				}
				else
				{
					System.err.println("message integrity check passed");
				}
			}
			else
			{
				System.err.println("no message integrity check");
			}
		}
		catch (PGPException e)
		{
			System.err.println(e);
			if (e.getUnderlyingException() != null)
			{
				e.getUnderlyingException().printStackTrace();
			}
		}
					}

	public static PGPPublicKey readPublicKey(String fileName) throws IOException, PGPException
	{
		InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
		PGPPublicKey pubKey = readPublicKey(keyIn);
		keyIn.close();
		return pubKey;
	}

	/**
	 * Search a secret key ring collection for a secret key corresponding to keyID if it
	 * exists.
	 * 
	 * @param pgpSec a secret key ring collection.
	 * @param keyID keyID we want.
	 * @param pass passphrase to decrypt secret key with.
	 * @return
	 * @throws PGPException
	 * @throws NoSuchProviderException
	 */
	static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass)
			throws PGPException, NoSuchProviderException
			{
		PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);

		if (pgpSecKey == null)
		{
			return null;
		}

		return pgpSecKey.extractPrivateKey(pass, "SC");
			}



	/**
	 * A simple routine that opens a key ring file and loads the first available key
	 * suitable for encryption.
	 * 
	 * @param input
	 * @return
	 * @throws IOException
	 * @throws PGPException
	 */
	public static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException
	{
		PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
				PGPUtil.getDecoderStream(input));

		//
		// we just loop through the collection till we find a key suitable for encryption, in the real
		// world you would probably want to be a bit smarter about this.
		//

		Iterator keyRingIter = pgpPub.getKeyRings();
		while (keyRingIter.hasNext())
		{
			PGPPublicKeyRing keyRing = (PGPPublicKeyRing)keyRingIter.next();

			Iterator keyIter = keyRing.getPublicKeys();
			while (keyIter.hasNext())
			{
				PGPPublicKey key = (PGPPublicKey)keyIter.next();

				if (key.isEncryptionKey())
				{
					return key;
				}
			}
		}

		throw new IllegalArgumentException("Can't find encryption key in key ring.");
	}


	public static byte[] encryptWithPGPKey(byte[] clearData, byte[] publicKey, boolean armor, boolean withIntegrityCheck) 
			throws IOException, PGPException, NoSuchProviderException{
		initialize();

		InputStream keyIn = new ByteArrayInputStream(publicKey);
		PGPPublicKey key = readPublicKey(keyIn);
		keyIn.close();


		String fileName= PGPLiteralData.CONSOLE;

		byte[] compressedData = compress(clearData, fileName, COMPRESSION_ALG);

		ByteArrayOutputStream bOut = new ByteArrayOutputStream();

		OutputStream out = bOut;
		if (armor)
		{
			out = new ArmoredOutputStream(out);
		}

		PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(ENCRYPTION_ALG, withIntegrityCheck, new SecureRandom(), "SC");
		//PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(ENCRYPTION_ALG, false, new SecureRandom(), "SC");
		encGen.addMethod(key);
		
		OutputStream encOut = encGen.open(out, compressedData.length);
		Log.i("WRITE DT", CryptoUtil.toHex(compressedData));
		encOut.write(compressedData);
		
		encOut.close();

		if (armor)
		{
			out.close();
		}

		return bOut.toByteArray();
	}

	public static byte[] decryptWithPGPKey(byte[] encrypted, byte[] secretKey, char[] passwd)
			throws IOException, NoSuchProviderException
			{
		initialize();

		InputStream in = new ByteArrayInputStream(encrypted);
		InputStream keyIn = new ByteArrayInputStream(secretKey);

		in = PGPUtil.getDecoderStream(in);
		ByteArrayOutputStream fOut = new ByteArrayOutputStream(); ;
		try
		{
			PGPObjectFactory pgpF = new PGPObjectFactory(in);
			PGPEncryptedDataList    enc;

			Object                  o = pgpF.nextObject();
			//
			// the first object might be a PGP marker packet.
			//
			if (o instanceof PGPEncryptedDataList)
			{
				enc = (PGPEncryptedDataList)o;
			}
			else
			{
				enc = (PGPEncryptedDataList)pgpF.nextObject();
			}

			//
			// find the secret key
			//
			Iterator                    it = enc.getEncryptedDataObjects();
			PGPPrivateKey               sKey = null;
			PGPPublicKeyEncryptedData   pbe = null;
			PGPSecretKeyRingCollection  pgpSec = new PGPSecretKeyRingCollection(
					PGPUtil.getDecoderStream(keyIn));

			while (sKey == null && it.hasNext())
			{
				pbe = (PGPPublicKeyEncryptedData)it.next();

				sKey = findSecretKey(pgpSec, pbe.getKeyID(), passwd);
			}

			if (sKey == null)
			{
				throw new IllegalArgumentException("secret key for message not found.");
			}

			InputStream         clear = pbe.getDataStream(sKey, "SC");

			PGPObjectFactory    plainFact = new PGPObjectFactory(clear);

			Object              message = plainFact.nextObject();

			if (message instanceof PGPCompressedData)
			{
				PGPCompressedData   cData = (PGPCompressedData)message;
				Log.w("READ CD","compressed data");
				PGPObjectFactory    pgpFact = new PGPObjectFactory(cData.getDataStream());

				message = pgpFact.nextObject();
			}

			if (message instanceof PGPLiteralData)
			{
				PGPLiteralData ld = (PGPLiteralData)message;
				
				InputStream unc = ld.getInputStream();
               

                Streams.pipeAll(unc, fOut);
                fOut.close();

				/*String outFileName = ld.getFileName();
							if (outFileName.length() == 0)
							{
								/*



								PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject();

								return Streams.readAll(ld.getInputStream());*/
				/*outFileName = defaultFileName;
							}

							InputStream unc = ld.getInputStream();
							OutputStream fOut = new BufferedOutputStream(new FileOutputStream(outFileName));

							Streams.pipeAll(unc, fOut);

							fOut.close();*/
			}
			else if (message instanceof PGPOnePassSignatureList)
			{
				throw new PGPException("encrypted message contains a signed message - not literal data.");
			}
			else
			{
				throw new PGPException("message is not a simple encrypted file - type unknown.");
			}

			if (pbe.isIntegrityProtected())
			{
				if (!pbe.verify())
				{
					System.err.println("message failed integrity check");
				}
				else
				{
					System.err.println("message integrity check passed");
				}
			}
			else
			{
				System.err.println("no message integrity check");
			}
		}
		catch (PGPException e)
		{
			System.err.println(e);
			if (e.getUnderlyingException() != null)
			{
				e.getUnderlyingException().printStackTrace();
			}
		}
		keyIn.close();

		return fOut.toByteArray();//Streams.readAll(ld.getInputStream());
	}
	
	public static void encryptLarge(byte[] clearData, byte[] publicKey, boolean armor, boolean withIntegrityCheck)
			throws IOException, PGPException, NoSuchProviderException{
		initialize();

		InputStream keyIn = new ByteArrayInputStream(publicKey);
		PGPPublicKey encKey = readPublicKey(keyIn);
		keyIn.close();


		/*String fileName= PGPLiteralData.CONSOLE;

		byte[] compressedData = compress(clearData, fileName, COMPRESSION_ALG);*/

		ByteArrayOutputStream bOut = new ByteArrayOutputStream();

		OutputStream out = bOut;
		if (armor)
		{
			out = new ArmoredOutputStream(out);
		}
		PGPEncryptedDataGenerator   cPk = new PGPEncryptedDataGenerator(ENCRYPTION_ALG, withIntegrityCheck, new SecureRandom(), "BC");
        
        cPk.addMethod(encKey);
        
        OutputStream                cOut = cPk.open(out, new byte[1 << 16]);
        File sdCard = Environment.getExternalStorageDirectory();
        PGPCompressedDataGenerator  comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);
                                                                        
        PGPUtil.writeFileToLiteralData(comData.open(cOut), PGPLiteralData.BINARY, new File(sdCard.getAbsolutePath() + "/ForAp/temp.txt"), new byte[1 << 16]);
        
        comData.close();
        
        cOut.close();

        if (armor)
        {
            out.close();
        }

		//return bOut.toByteArray();
	}
	
	/**
     * write out the passed in file as a literal data packet in partial packet format.
     * 
     * @param out
     * @param fileType the LiteralData type for the file.
     * @param file
     * @param buffer buffer to be used to chunk the file into partial packets.
     * 
     * @throws IOException
     */
   /* public static void writeFileToLiteralData(
        OutputStream    out,
        char            fileType,
        ByteArrayInputStream            in,
        byte[]          buffer)
        throws IOException
    {
        PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
        OutputStream pOut = lData..open(out, fileType, in.getName(), new Date(file.lastModified()), buffer);
        pipeFileContents(in, pOut, buffer.length);
    }
    
    private static void pipeFileContents(ByteArrayInputStream fIn, OutputStream pOut, int bufSize) throws IOException
    {
        byte[] buf = new byte[bufSize];

        int len;
        while ((len = fIn.read(buf)) > 0)
        {
            pOut.write(buf, 0, len);
        }

        pOut.close();
        fIn.close();
    }
*/

	public static byte[] encryptWithPassphrase(byte[] clearData, char[]  passPhrase, boolean armor, boolean withIntegrityCheck) 
			throws IOException, PGPException, NoSuchProviderException{
		initialize();
		String fileName= PGPLiteralData.CONSOLE;


		byte[] compressedData = compress(clearData, fileName, COMPRESSION_ALG);

		ByteArrayOutputStream bOut = new ByteArrayOutputStream();

		OutputStream out = bOut;
		if (armor)
		{
			out = new ArmoredOutputStream(out);
		}

		PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(ENCRYPTION_ALG, withIntegrityCheck, new SecureRandom(), "SC");
		//huh??
		encGen.addMethod(passPhrase);

		//OutputStream encOut = encGen.open(out, compressedData.length);
		OutputStream encOut = encGen.open(out, new byte[1 << 16]);
		encOut.write(compressedData);
		encOut.close();

		if (armor)
		{
			out.close();
		}

		return  bOut.toByteArray();
	}

	public static byte[] decryptWithPassphrase(byte[] encrypted, char[] passPhrase)
			throws IOException, PGPException, NoSuchProviderException {
		initialize();
		InputStream in = new ByteArrayInputStream(encrypted);
		in = PGPUtil.getDecoderStream(in);
		PGPObjectFactory pgpF = new PGPObjectFactory(in);
		PGPEncryptedDataList enc = null;
		Object o = pgpF.nextObject();

		// the first object might be a PGP marker packet.
		//
		if (o instanceof PGPEncryptedDataList)
		{
			enc = (PGPEncryptedDataList)o;
		}
		else
		{
			enc = (PGPEncryptedDataList)pgpF.nextObject();
		}

		PGPPBEEncryptedData pbe = (PGPPBEEncryptedData)enc.get(0);
		InputStream clear = pbe.getDataStream(passPhrase, "SC");
		PGPObjectFactory pgpFact = new PGPObjectFactory(clear);
		/*PGPCompressedData cData = (PGPCompressedData)pgpFact.nextObject();
		pgpFact = new PGPObjectFactory(cData.getDataStream());

		PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject();

		return Streams.readAll(ld.getInputStream());*/
		
		//
        // if we're trying to read a file generated by someone other than us
        // the data might not be compressed, so we check the return type from
        // the factory and behave accordingly.
        //
        o = pgpFact.nextObject();
        if (o instanceof PGPCompressedData)
        {
            PGPCompressedData   cData = (PGPCompressedData)o;

            pgpFact = new PGPObjectFactory(cData.getDataStream());

            o = pgpFact.nextObject();
        }
        
        PGPLiteralData ld = (PGPLiteralData)o;
        InputStream unc = ld.getInputStream();

        ByteArrayOutputStream fOut = new ByteArrayOutputStream();

        Streams.pipeAll(unc, fOut);

        fOut.close();

        if (pbe.isIntegrityProtected())
        {
            if (!pbe.verify())
            {
                System.err.println("message failed integrity check");
            }
            else
            {
                System.err.println("message integrity check passed");
            }
        }
        else
        {
            System.err.println("no message integrity check");
        }
        return fOut.toByteArray();
	}


	private static byte[] compress(byte[] clearData, String fileName, int algorithm) throws IOException {
		ByteArrayOutputStream bOut = new ByteArrayOutputStream();
		PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(algorithm);
		OutputStream cos = comData.open(bOut); // open it with the final destination

		PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
		// we want to generate compressed data. This might be a user option later,
		// in which case we would pass in bOut.
		OutputStream  pOut = lData.open(cos, // the compressed output stream
				PGPLiteralData.BINARY,
				fileName,  // "filename" to store
				clearData.length, // length of clear data
				new Date()  // current time
				);

		pOut.write(clearData);
		pOut.close();

		comData.close();

		return bOut.toByteArray();
	}
	
	private static byte[] compressLarge(byte[] clearData, String fileName, int algorithm) throws IOException {
		ByteArrayOutputStream bOut = new ByteArrayOutputStream();
		PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(algorithm);
		OutputStream cos = comData.open(bOut); // open it with the final destination

		PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
		// we want to generate compressed data. This might be a user option later,
		// in which case we would pass in bOut.
		OutputStream  pOut = lData.open(cos, // the compressed output stream
				PGPLiteralData.BINARY,
				fileName,  // "filename" to store
				clearData.length, // length of clear data
				new Date()  // current time
				);

		pOut.write(clearData);
		pOut.close();

		comData.close();

		return bOut.toByteArray();
	}
	

	static byte[] compressFile(String fileName, int algorithm) throws IOException
	{
		ByteArrayOutputStream bOut = new ByteArrayOutputStream();
		PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(algorithm);
		PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName));
		comData.close();
		return bOut.toByteArray();
	}

	public static String readSecretKeyId(byte[] data) throws IOException, PGPException{
		PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
				PGPUtil.getDecoderStream(new ByteArrayInputStream(data)));

		//
		// we just loop through the collection till we find a key suitable for encryption, in the real
		// world you would probably want to be a bit smarter about this.
		//

		Iterator keyRingIter = pgpSec.getKeyRings();
		while (keyRingIter.hasNext()){
			PGPSecretKeyRing keyRing = (PGPSecretKeyRing)keyRingIter.next();
			Iterator keyIter = keyRing.getSecretKeys();
			while (keyIter.hasNext()){
				PGPSecretKey key = (PGPSecretKey)keyIter.next();
				Iterator userIdIter  = key.getUserIDs();
				while(userIdIter.hasNext()){
					String id = (String) userIdIter.next();
					return id;
				}
			}
		}
		throw new IllegalArgumentException("Can't find encryption key in key ring.");
	}

	public static String readPublicKeyId(byte[] data) throws IOException, PGPException{
		PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
				PGPUtil.getDecoderStream(new ByteArrayInputStream(data)));

		//
		// we just loop through the collection till we find a key suitable for encryption, in the real
		// world you would probably want to be a bit smarter about this.
		//

		Iterator keyRingIter = pgpPub.getKeyRings();
		while (keyRingIter.hasNext()){
			PGPPublicKeyRing keyRing = (PGPPublicKeyRing)keyRingIter.next();
			Iterator keyIter = keyRing.getPublicKeys();
			while (keyIter.hasNext()){
				PGPPublicKey key = (PGPPublicKey)keyIter.next();
				Iterator userIdIter  = key.getUserIDs();
				while(userIdIter.hasNext()){
					String id = (String) userIdIter.next();
					return id;
				}
			}
		}
		throw new IllegalArgumentException("Can't find encryption key in key ring.");
	}
}
